{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Learn BitcoinLib in 10 minutes\n",
    "\n",
    "A short walk through all the important BitcionLib classes: create keys, transactions and wallets using this library.\n",
    "\n",
    "You can run and experiment with the code examples if you have installed [Jupyter](https://jupyter.org/install)"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Keys\n",
    "\n",
    "With the Key class you can create and manage private and public cryptographic keys.\n",
    "\n",
    "Run the code below to create a random key, then show the class data with the info() method which is handy for\n",
    "developing and debugging your code."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import Key\n",
    "k = Key()\n",
    "k.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "As you can see a private key, public key, address and WIF (Wallet Import Format) are all created as part of the \n",
    "Key representation.\n",
    "\n",
    "You can also see a 'point x' and 'point y' as a private key is nothing more then a point on the \n",
    "[Secp256k1](https://en.bitcoin.it/wiki/Secp256k1) curve. \n",
    "\n",
    "If you have already a private key WIF you can use this to create a Key class. "
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import Key\n",
    "wif = 'KyAoQkmmoAgdC8YXamgpqFb2R8j6g5jiBnGdJo62aDJCxstboTqS'\n",
    "k = Key(wif)\n",
    "print(k.address())"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "You can use the bip32_encrypt method to create an encrypted key. In the example below this key is used to \n",
    "recreate the original unencrypted key.\n",
    " "
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import Key\n",
    "k = Key()\n",
    "print(k.private_hex)\n",
    "encrypted_wif = k.bip38_encrypt('secret')\n",
    "print(encrypted_wif)\n",
    "\n",
    "k_import = Key(encrypted_wif, passphrase='secret')\n",
    "print(k_import.private_hex)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "And of course the Key class can also represent other networks and encodings, such as Litecoin or the\n",
    "bech32 encoding used in segwit.\n",
    " "
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import Key\n",
    "k = Key(network='litecoin')\n",
    "print(k.address())\n",
    "print(k.address(encoding='bech32'))\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## HDKey\n",
    "\n",
    "The HDKey class, or hierarchical deterministic key class, is a child of the Key class and mainly adds a chain code. \n",
    "This chain code allows to create key structures or related which can be derived from a single master key.\n",
    "\n",
    "The creation of a random HDKey is just as simple as a normal Key but it gives a range of extra possibilities.\n",
    "\n",
    "When you run the code below and check the info() output near 'Extended Key' you can find the extra's the HDKey provides.\n",
    "First the chain code, which is also random generated just as the key. Next the depth and child index allowing to \n",
    "create levels of keys. And final the WIF representing all HDKey info in an exchangeable string."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import HDKey\n",
    "k = HDKey(witness_type='segwit')\n",
    "k.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "So let's try to import a HDKey wif and create a private child key and the a public child key."
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import HDKey\n",
    "\n",
    "extended_wif = 'zprvAWgYBBk7JR8Gk4CexKBHgzfYiYXgV71Ybi2tJFU2yDn8RgiqsviqT4eYPE9LofWMdrSkYmWciMtiD7jqA5dccDLnJj' \\\n",
    "               'DSMghhGRv41vHo9yx'\n",
    "k = HDKey(extended_wif)\n",
    "ck = k.child_private(10)\n",
    "print(\"ck.private_hex: %s\" % ck.private_hex)\n",
    "print(\"ck.depth: %s\" % ck.depth)\n",
    "ck_pub = ck.child_public(0)\n",
    "print(\"ck_pub.private_hex: %s\" % ck_pub.private_hex)\n",
    "print(\"ck_pub.public_hex: %s\" % ck_pub.public_hex)\n",
    "print(\"ck_pub.depth: %s\" % ck_pub.depth)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "As you can see the depth increases with 1 with every derived child key, and when you derive a public key the private\n",
    "key is not available anymore.\n",
    "\n",
    "While this is all very interesting I think, please remember you not have to care of any of this if you just using the\n",
    "HDWallet class. The HDWallet class handles key derivation in the background for you.\n",
    "\n",
    "The HDKey class has various methods to create key paths used in most modern wallet software today."
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import HDKey\n",
    "\n",
    "prv_masterkey = HDKey()\n",
    "pub_masterkey = prv_masterkey.public_master()\n",
    "print(\"Public masterkey to exchange (method 1): %s\" % pub_masterkey.wif())\n",
    "pub_masterkey = prv_masterkey.subkey_for_path(\"m/44'/0'/0'\")\n",
    "print(\"Public masterkey to exchange (method 2): %s\" % pub_masterkey.wif())\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Other key related classes: The Mnemonic and Address class\n",
    "\n",
    "A Mnemonic sentence is an easy way for us humans to read and exchange private keys. With bitcoinlib you can\n",
    "create Mnemonic phrases and use them to create keys or wallets."
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.mnemonic import Mnemonic\n",
    "from bitcoinlib.keys import HDKey\n",
    "\n",
    "phrase = Mnemonic().generate()\n",
    "print(phrase)\n",
    "k = HDKey.from_passphrase(phrase)\n",
    "print(k.private_hex)\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% \n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Use the address class to create an address or to analyse address information."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.keys import Address\n",
    "address = 'bc1q96zj7hv097x9u9f86azlk49ffxak7zltyfghld'\n",
    "a = Address.import_address(address)\n",
    "print(a.as_json())\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% \n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Transactions\n",
    "\n",
    "Transactions represent the transaction of value and are stored on the Blockchain. A transaction has 1 or more inputs \n",
    "to unlock previous outputs and 1 or more outputs containing locking scripts. These locking script can be unlocked with a \n",
    "private key and then spent again in inputs of a new transaction.\n",
    "\n",
    "Let's create a simple transaction."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.transactions import Transaction\n",
    "from bitcoinlib.keys import HDKey\n",
    "\n",
    "t = Transaction()\n",
    "prev_hash = '9c81f44c29ff0226f835cd0a8a2f2a7eca6db52a711f8211b566fd15d3e0e8d4'\n",
    "t.add_input(prev_hash, output_n=0)\n",
    "k = HDKey()\n",
    "t.add_output(100000, k.address())\n",
    "t.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% \n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "There are many way to create transactions in most cases you will get them for the blockchain or create them\n",
    "with the HDWallet class.\n",
    "\n",
    "Below is an example of how to parse a raw transaction."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.transactions import Transaction\n",
    "\n",
    "rawtx = \"010000000001015f171218b2e273be55af4f1cf0a56c0499b48b098d16ebdc68c62db78c55765a0100000000ffffff000200e1f505\" \\\n",
    "        \"0000000017a9140db01b8486f63ef80f02fe78bada7680c46c11ef8730f10801000000001600141dfba959940495c3a92cbb80b0b5\" \\\n",
    "        \"0246cfe0f11702473044022004eb67e91dc04179a367d99c0d65617cda385c313e79d717f8ade695a5731b8c02207a273d8592d815\" \\\n",
    "        \"9d6f587a0db993ab4b4a030fbfa390229b490d789a77b8c8540121029422dbe194e42bac01e94925cf8b619f0fd4aa5d0181633659\" \\\n",
    "        \"e7deed79eb5b7a00000000\"\n",
    "t = Transaction.import_raw(rawtx)\n",
    "t.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Service providers\n",
    "\n",
    "The library can get transaction and blockchain information from various online or locally installed\n",
    "providers. So you can get check if a transaction output (UTXO) is spent already, update a wallet's \n",
    "address balance or push a new transaction to the network."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.services.services import Service\n",
    "\n",
    "srv = Service()\n",
    "print(\"Estimated transaction fee: %s\" % srv.estimatefee())\n",
    "print(\"Latest block: %s\" % srv.blockcount())"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "After a request with the Service class the results and errors are stored in the class. If you for instance request an\n",
    "unknown transaction, the request returns False, the Service().results is empty and the errors can be found in \n",
    "Service().errors."
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.services.services import Service\n",
    "\n",
    "srv = Service()\n",
    "unknown_txid = '9c81f44c29ff0226f835cd0a8a2f2a7eca6db52a711f8211b566fd15d3e0e8d4'\n",
    "srv.gettransaction(unknown_txid)\n",
    "print(srv.results)\n",
    "print(srv.errors)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Wallets\n",
    "\n",
    "The HDWallet class combines all classes we've seen so far. The wallet class is used to store and manage keys, \n",
    "check for new utxo's, create, sign and send transactions.\n",
    "\n",
    "Creating a bitcoin wallet is very easy, just use the create() method and pass a wallet name."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from bitcoinlib.wallets import HDWallet\n",
    "w = HDWallet.create('jupyter-test-wallet')\n",
    "w.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "The create() methods raises an error if the wallet already exists, so if you are not sure use the wallet_create_or_open\n",
    "method.\n",
    "\n",
    "And now let's conclude with a Bitcoin segwit testnet wallet and a send a real transaction."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "text": [
      "Deposit to address tb1qxedjhe6ckzl4mf60adzknuh4336hazrea9rgjh to get started\n"
     ],
     "output_type": "stream"
    }
   ],
   "source": [
    "from bitcoinlib.wallets import wallet_create_or_open\n",
    "\n",
    "w = wallet_create_or_open('bitcoinlib-testnet1', network='testnet', witness_type='segwit')\n",
    "wk = w.new_key()\n",
    "print(\"Deposit to address %s to get started\" % wk.address)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Now go to a Bitcoin [testnet faucet](https://bitcoinfaucet.uo1.net) to get some coins.\n",
    "\n",
    "Check if the testnet coins are successfully send, so we can start creating a transaction."
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "name": "stdout",
     "text": [
      "=== WALLET ===\n",
      " ID                             1\n",
      " Name                           bitcoinlib-testnet1\n",
      " Owner                          \n",
      " Scheme                         bip32\n",
      " Multisig                       False\n",
      " Witness type                   segwit\n",
      " Main network                   testnet\n",
      " Latest update                  2020-01-16 21:40:44.947327\n",
      "\n",
      "= Wallet Master Key =\n",
      " ID                             1\n",
      " Private                        True\n",
      " Depth                          0\n",
      "\n",
      "- NETWORK: testnet -\n",
      "- - Keys\n",
      "    6 m/84'/1'/0'/0/0              tb1q6qsl0gxys42tp85nuqs69q7ye23n7sslac8gqc    address index 0                     0.00000000 TBTC\n",
      "    7 m/84'/1'/0'/0/1              tb1qxgjgla2dgw0ngheh89vjfs4etz8xl5m86xgupt    address index 1                     0.00000000 TBTC\n",
      "    8 m/84'/1'/0'/0/2              tb1qppduulzc9wfwy9nexyr60q04ed0fr6vzv5jgut    address index 2                     0.00000000 TBTC\n",
      "    9 m/84'/1'/0'/0/3              tb1q48cauqexy5zs20sesrdyduqavlj9jvghw7mmz0    address index 3                     0.00000000 TBTC\n",
      "   10 m/84'/1'/0'/0/4              tb1qhdsccs0pav4gg5ssnncakd4w4uf94galt6yjkf    address index 4                     0.00000000 TBTC\n",
      "   11 m/84'/1'/0'/0/5              tb1qxedjhe6ckzl4mf60adzknuh4336hazrea9rgjh    address index 5                     0.00010000 TBTC\n",
      "\n",
      "- - Transactions Account 0 (1)\n",
      "3963a36d204d5eb1913734ba83b9e82df24ec73f581ee4d24ee716edb822e3d1 tb1qxedjhe6ckzl4mf60adzknuh4336hazrea9rgjh        5         10000 U \n",
      "\n",
      "= Balance Totals (includes unconfirmed) =\n",
      "testnet              (Account 0)               0.00010000 TBTC\n",
      "\n",
      "\n"
     ],
     "output_type": "stream"
    }
   ],
   "source": [
    "from bitcoinlib.wallets import wallet_create_or_open\n",
    "\n",
    "w = wallet_create_or_open('bitcoinlib-testnet1', network='testnet', witness_type='segwit')\n",
    "n_utxos = w.utxos_update()\n",
    "if n_utxos:\n",
    "    print(\"Found new unspent outputs (UTXO's), we are ready to create a transaction\")\n",
    "w.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "The utxos_update() method only checks for new unspent outputs for existing keys. Two other methods to receive \n",
    "transaction information for your wallet are the transactions_update() and scan() method. Transactions_update \n",
    "retrieves all transactions from the service providers for your wallet's key: incoming and outgoing.\n",
    "\n",
    "The scan() method also generates new keys/addresses and updates all transactions.\n",
    "\n",
    "Now we have a wallet with coins and can create a transaction and send some coins. The send_to() method\n",
    "creates a transactions and then broadcasts the signed transactions to the network. "
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "text": [
      "Transaction b8f3072a0768e2ae91407e4f2817008d41e7ba1dbb8ce911b320c13bec78d9c9\n",
      "Date: None\n",
      "Network: testnet\n",
      "Version: 1\n",
      "Witness type: segwit\n",
      "Status: unconfirmed\n",
      "Verified: True\n",
      "Inputs\n",
      "- tb1qxedjhe6ckzl4mf60adzknuh4336hazrea9rgjh 10000 3963a36d204d5eb1913734ba83b9e82df24ec73f581ee4d24ee716edb822e3d1 0\n",
      "  segwit sig_pubkey; sigs: 1 (1-of-1) valid\n",
      "Outputs\n",
      "- tb1qxgjgla2dgw0ngheh89vjfs4etz8xl5m86xgupt 4000 p2wpkh U\n",
      "- tb1q7tega57rca4lpa7p0x5nvgu892azrkq97t37qm 5000 p2wpkh U\n",
      "Size: 141\n",
      "Vsize: 141\n",
      "Fee: 1000\n",
      "Confirmations: 0\n",
      "Pushed to network: True\n",
      "Wallet: bitcoinlib-testnet1\n",
      "\n",
      "\n"
     ],
     "output_type": "stream"
    }
   ],
   "source": [
    " \n",
    "from bitcoinlib.wallets import wallet_create_or_open\n",
    "\n",
    "w = wallet_create_or_open('bitcoinlib-testnet1', network='testnet', witness_type='segwit')\n",
    "t = w.send_to('tb1qprqnf4dqwuphxs9xqpzkjdgled6eeptn389nec', 4000, fee=1000)\n",
    "t.info()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": false
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "When you run this code you should receive a transaction ID and t.pushed equals True. You can also create\n",
    "an outgoing transactions with the HDWallet.send() method. To spent all available UTXO's and empty a wallet\n",
    "the sweep() method is used.\n",
    "\n",
    "This concludes this brief overview of BitcoinLib. Check out the \n",
    "[examples](https://github.com/1200wd/bitcoinlib/tree/master/examples) on GitHub or the \n",
    "[documentation](https://bitcoinlib.readthedocs.io/en/latest/?badge=latest) for further exploration.\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "source": [],
    "metadata": {
     "collapsed": false
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}